﻿/*
Copyright © 2011 François Karman

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

See <license.txt> for the complete license of the software.
*/

using System;
using System.Collections;
using System.Collections.Generic;

namespace Simple.Storage
{
    /// <summary>
    /// Provides a read-only layer around an existing collection.
    /// </summary>
    /// <typeparam name="T">
    /// The type of the elements in the collection.
    /// </typeparam>
    public class ReadOnlyCollection<T> : ICollection<T>
    {
        /// <summary>
        /// The encapsulated collection.
        /// </summary>
        private readonly ICollection<T> encapsulated;

        /// <summary>
        /// Initializes a new instance of the ReadOnlyCollection class.
        /// </summary>
        /// <param name="encapsulated">
        /// The encapsulated collection.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="encapsulated"/> parameter is <c>null</c>.
        /// </exception>
        public ReadOnlyCollection(ICollection<T> encapsulated)
        {
            if (encapsulated == null)
            {
                throw new ArgumentNullException("encapsulated");
            }

            this.encapsulated = encapsulated;
        }

        /// <summary>
        /// Gets the number of elements contained in this collection.
        /// </summary>
        public int Count
        {
            get { return this.encapsulated.Count; }
        }

        /// <summary>
        /// Gets a value indicating whether this collection is read-only.
        /// </summary>
        /// <value>Always <c>true</c>.</value>
        public bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// Adds an item to this collection - always raises <see cref="NotSupportedException"/>.
        /// </summary>
        /// <param name="item">The object to add to this collection.</param>
        /// <exception cref="NotSupportedException">
        /// The collection is read-only.
        /// </exception>
        public void Add(T item)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Removes all items from this collection - always raises <see cref="NotSupportedException"/>.
        /// </summary>
        /// <exception cref="NotSupportedException">
        /// The collection is read-only.
        /// </exception>
        public void Clear()
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from this collection
        /// - always raises <see cref="NotSupportedException"/>.
        /// </summary>
        /// <param name="item">The object to remove from this collection.</param>
        /// <returns>Always raises <see cref="NotSupportedException"/>.</returns>
        /// <exception cref="NotSupportedException">
        /// The collection is read-only.
        /// </exception>
        public bool Remove(T item)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Determines whether this collection contains a specific value.
        /// </summary>
        /// <param name="item">The object to locate in this collection.</param>
        /// <returns>
        /// <c>true</c> if item is found in this collection;
        /// otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(T item)
        {
            return this.encapsulated.Contains(item);
        }

        /// <summary>
        /// Copies the elements of this collection to an <see cref="Array"/>,
        /// starting at a particular index.
        /// </summary>
        /// <param name="array">
        /// The one-dimensional <see cref="Array"/> that is the destination of the elements
        /// copied from this collection. The <see cref="Array"/> must have zero-based indexing.
        /// </param>
        /// <param name="arrayIndex">
        /// The zero-based index in array at which copying begins.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="array"/> parameter is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// The <paramref name="arrayIndex"/> parameter is less than 0.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <paramref name="array"/> is multidimensional.
        /// -or-The number of elements in the source collection is greater than the available space
        /// from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.
        /// -or-Type T cannot be cast automatically to the type of the destination
        /// <paramref name="array"/>.
        /// </exception>
        public void CopyTo(T[] array, int arrayIndex)
        {
            this.encapsulated.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<T> GetEnumerator()
        {
            return this.encapsulated.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="IEnumerator"/> that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this.encapsulated).GetEnumerator();
        }
    }
}
